import { Inject, Provide } from '@midwayjs/core'
import { InjectEntityModel } from '@midwayjs/typeorm'
import { Repository } from 'typeorm'

import { SysMenuEntity, SysUserEntity } from '@/entity'

import { StateService } from './state.service'

@Provide()
export class LoginUserService {
  @Inject()
  stateService: StateService

  @InjectEntityModel(SysUserEntity)
  userModel: Repository<SysUserEntity>

  @InjectEntityModel(SysMenuEntity)
  menuModel: Repository<SysMenuEntity>

  async getCurrentUser() {
    const jwtPayload = this.stateService.getJwtPayload()

    const { roles, ...rest } = await this.userModel.findOne({
      relations: {
        roles: {
          menus: true
        }
      },
      where: { userName: jwtPayload.userName }
    })

    const user = {
      menus: [] as IUserMenu[],
      roles: [] as string[],
      permissions: [] as string[],
      user: rest
    }

    if (roles && roles.length) {
      user.roles = roles.map(v => v.roleKey)

      if (rest.userId === '1') {
        // 主账号拥有全部权限
        user.permissions = ['*:*:*']

        const menus = await this.menuModel.find()
        user.menus = await this.transformMenus(menus)
      } else {
        const permissions = new Set<string>()
        const menus = new Map()

        for (const role of roles) {
          if (role.menus && role.menus.length) {
            for (const menu of role.menus) {
              permissions.add(menu.perms)
              menus.set(menu.menuId, menu)
            }
          }
        }

        user.permissions = Array.from(permissions)
        user.menus = await this.transformMenus(Object.values(menus))
      }
    }

    return user
  }

  private async transformMenus(menus: SysMenuEntity[]) {
    // 过滤按钮权限
    menus = menus.filter(v => v.menuType !== 'F')

    const data = new Set<IUserMenu>()

    for (const menu of menus) {
      let alwaysShow = false
      let children = null
      let path = menu.path
      let redirect = menu.redirect
      let component = ''

      const childMenus = menus.filter(v => v.parentId === menu.menuId)
      if (childMenus.length > 0) {
        alwaysShow = true
        children = []
      }

      // 父路由必须以 `/` 开始
      if (menu.parentId === '0' && !path.startsWith('/')) {
        path = `/${path}`
      }

      // 重定向必须以 `/` 开始
      if (redirect && !redirect.startsWith('/')) {
        redirect = `/${redirect}`
      }

      if (menu.component) {
        component = menu.component
      } else if (menu.parentId === '0') {
        component = 'DefaultLayout'
      } else {
        component = 'ParentLayout'
      }

      data.add({
        key: menu.menuId,
        parentKey: menu.parentId,
        path,
        name: '',
        redirect,
        component,
        meta: {
          title: menu.menuName,
          icon: menu.icon,
          sort: menu.orderNum,
          hidden: menu.visible === '1',
          noCache: menu.isCache === 1,
          alwaysShow
        },
        children
      })
    }

    return Array.from(data)
  }
}
